import {
  Viewer,
  ScreenSpaceEventHandler,
  ScreenSpaceEventType,
  Cartesian3,
  Entity,
  CallbackProperty,
  Color,
  defined,
  DeveloperError,
  Event,
  Cartographic,
  Math as CesiumMath,
} from "cesium";

/**
 * 航路点绘制工具
 * @function viewerWaypointDrawerMixin
 * @param {Viewer} viewer - Cesium Viewer实例
 * @param {Object} [options] - 配置选项
 * @param {Color} [options.pointColor=Color.YELLOW] - 航点颜色
 * @param {Color} [options.lineColor=Color.BLUE] - 连线颜色
 * @param {number} [options.pointSize=10] - 航点大小
 * @param {number} [options.lineWidth=3] - 连线宽度
 *
 * @exception {DeveloperError} viewer是必须参数
 * @exception {DeveloperError} waypointDrawEnabled已由其他mixin定义
 * @exception {DeveloperError} waypointDrawComplete已由其他mixin定义
 */
export function viewerWaypointDrawerMixin(
  viewer: Viewer,
  options: {
    pointColor: Color;
    lineColor: Color;
    pointSize: number;
    lineWidth: number;
  }
) {
  //>>includeStart('debug', pragmas.debug);
  if (!defined(viewer)) {
    throw new DeveloperError("viewer是必须参数");
  }
  if (viewer.hasOwnProperty("waypointDrawEnabled")) {
    throw new DeveloperError("waypointDrawEnabled已由其他mixin定义");
  }
  if (viewer.hasOwnProperty("waypointDrawComplete")) {
    throw new DeveloperError("waypointDrawComplete已由其他mixin定义");
  }
  //>>includeEnd('debug');

  options = options || {};
  const pointColor = options.pointColor || Color.YELLOW;
  const lineColor = options.lineColor || Color.BLUE;
  const pointSize = options.pointSize || 10;
  const lineWidth = options.lineWidth || 3;

  const positions: Cartesian3[] = [];
  // 局部变量
  let isDrawing = false;
  const points: Entity[] = [];
  let tempLine: Entity | undefined;
  const drawCompleteEvent = new Event();
  let handler: ScreenSpaceEventHandler | undefined;

  // 定义viewer属性
  Object.defineProperties(viewer, {
    /**
     * 获取或设置是否启用绘制
     * @memberof viewerWaypointDrawerMixin.prototype
     * @type {boolean}
     */
    waypointDrawEnabled: {
      get: function () {
        return isDrawing;
      },
      set: function (value) {
        if (value !== isDrawing) {
          if (value) {
            startDrawing();
          } else {
            stopDrawing();
          }
          isDrawing = value;
        }
      },
    },

    /**
     * 获取绘制完成事件
     * @memberof viewerWaypointDrawerMixin.prototype
     * @type {Event}
     */
    waypointDrawComplete: {
      get: function () {
        return drawCompleteEvent;
      },
    },
  });

  // 开始绘制
  function startDrawing() {
    handler = new ScreenSpaceEventHandler(viewer.scene.canvas);

    handler.setInputAction(function (
      movement: ScreenSpaceEventHandler.PositionedEvent
    ) {
      const cartesian = viewer.camera.pickEllipsoid(
        movement.position,
        viewer.scene.globe.ellipsoid
      );

      if (!cartesian) return;

      positions.push(cartesian);
      const point = viewer.entities.add({
        position: cartesian,
        point: {
          color: pointColor,
          pixelSize: pointSize,
          outlineColor: Color.WHITE,
          outlineWidth: 2,
        },
      });

      points.push(point);
      updateTempLine();
    },
      ScreenSpaceEventType.LEFT_CLICK);

    handler.setInputAction(function () {
      finishDrawing();
    }, ScreenSpaceEventType.RIGHT_CLICK);

    handler.setInputAction(function (
      movement: ScreenSpaceEventHandler.MotionEvent
    ) {
      if (points.length === 0) return;

      const cartesian = viewer.camera.pickEllipsoid(
        movement.endPosition,
        viewer.scene.globe.ellipsoid
      );

      if (!cartesian) return;

      if (!tempLine) {
        tempLine = viewer.entities.add({
          polyline: {
            positions: new CallbackProperty(getCurrentPositions, false),
            width: lineWidth,
            material: lineColor,
          },
        });
      }
    },
      ScreenSpaceEventType.MOUSE_MOVE);
  }

  // 停止绘制
  function stopDrawing() {
    if (handler) {
      handler.destroy();
      handler = undefined;
    }
    clearPoints();
  }

  // 完成绘制
  function finishDrawing() {
    if (points.length === 0) return;
    const wps = positions.map((point) => {
      const cartographic = Cartographic.fromCartesian(point);
      return {
        lon: CesiumMath.toDegrees(cartographic.longitude),
        lat: CesiumMath.toDegrees(cartographic.latitude),
        alt: cartographic.height,
      };
    });
    const jsonText = JSON.stringify(wps, null, 2);
    copyToClipboard(jsonText);
    showNotification(`已采集${wps.length}个航点，数据已复制`);

    drawCompleteEvent.raiseEvent(wps);
    stopDrawing();
  }

  // 辅助函数
  function getCurrentPositions() {
    return positions;
  }

  function updateTempLine() {
    if (!tempLine && points.length > 1) {
      tempLine = viewer.entities.add({
        polyline: {
          positions: new CallbackProperty(getCurrentPositions, false),
          width: lineWidth,
          material: lineColor,
        },
      });
    }
  }

  function clearPoints() {
    points.forEach((p) => viewer.entities.remove(p));
    points.length = 0;
    if (tempLine) {
      viewer.entities.remove(tempLine);
      tempLine = undefined;
    }
  }

  function copyToClipboard(text: string) {
    const textarea = document.createElement("textarea");
    textarea.value = text;
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand("copy");
    document.body.removeChild(textarea);
  }

  function showNotification(message: string) {
    const element = document.createElement("div");
    element.style.cssText = `
      position: absolute;
      top: 20px;
      left: 50%;
      transform: translateX(-50%);
      padding: 10px 20px;
      background: rgba(0,0,0,0.7);
      color: white;
      border-radius: 5px;
      z-index: 9999;
    `;
    element.textContent = message;
    viewer.container.appendChild(element);
    setTimeout(() => element.remove(), 3000);
  }

  // 扩展destroy方法
  const originalDestroy = viewer.destroy;
  viewer.destroy = function () {
    stopDrawing();
    originalDestroy.call(viewer);
  };

  // 默认启用绘制
  startDrawing();
  isDrawing = true;
}

export default viewerWaypointDrawerMixin;
